package com.dhq.myapp.util.ask

import android.content.Context
import android.text.TextUtils
import android.util.Log
import com.dhq.myapp.bean.AsrResultEntity
import com.dhq.myapp.util.DataUtils
import com.dhq.myapp.util.http.HttpCallback
import com.dhq.myapp.util.http.OkHttpUtils
import org.json.JSONObject
import java.io.File
import java.io.FileInputStream
import java.io.FileWriter
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL
import kotlin.concurrent.thread

class AsrMain(private val mContext: Context) {

    private val METHOD_RAW = false // 默认以json方式上传音频文件

//    #AppID： 120609911
//    #API Key： wDxN8dlAcWqTJsGkSGugCJxY
//    #Secret Key： k20nIBnNKtos9O4Y8FvZfclWi9oufz4r

    // 填写网页上申请的appkey 如 $apiKey="g8eBUMSokVB1BHGmgxxxxxx"
    private val APP_KEY = "wDxN8dlAcWqTJsGkSGugCJxY"

    // 填写网页上申请的APP SECRET 如 $SECRET_KEY="94dc99566550d87f8fa8ece112xxxxx"
    private val SECRET_KEY = "k20nIBnNKtos9O4Y8FvZfclWi9oufz4r"

    // 需要识别的文件
    private val FILENAME = "16k.pcm"

    // 文件格式, 支持pcm/wav/amr 格式，极速版额外支持m4a 格式
//    private val FORMAT = FILENAME.substring(FILENAME.length - 3)
    private val FORMAT = "pcm"

    private var CUID = "1234567JAVA"

    // 采样率固定值
    private val RATE = 16000

    private var URL: String

    private var DEV_PID: Int

    //private var LM_ID: Int // 测试自训练平台需要打开此注释

    private var SCOPE: String=""

    // 初始化块 - 普通版参数
    init {
        URL = " http://vop.baidu.com/server_api " // 可以改为https
        // 1537 表示识别普通话，使用输入法模型。其它语种参见文档
        DEV_PID = 1537
        SCOPE = "audio_voice_assistant_get"
    }

    // 自训练平台参数（注释）
    /*
    init {
        // 自训练平台模型上线后，您会看见第二步："获取专属模型参数pid:8001，modelid:1234"，按照这个信息获取 dev_pid=8001，lm_id=1234
        DEV_PID = 8001
        LM_ID = 1234
    }
    */

    // 极速版参数（注释）
    /*
    init {
        URL = " http://vop.baidu.com/pro_api " // 可以改为https
        DEV_PID = 80001
        SCOPE = "brain_enhanced_asr"
    }
    */

    // 忽略scope检查，非常旧的应用可能没有（注释）
    /*
    init {
        SCOPE = null
    }
    */

    companion object {
//        @Throws(IOException::class, DemoException::class)
//        @JvmStatic
//        fun main(args: Array<String>) {
//            val demo = AsrMain()
//            // 填写下面信息
//            val result = demo.run()
//            println("识别结束：结果是：")
//            println(result)
//
//            // 如果显示乱码，请打开result.txt查看
//            val file = File("result.txt")
//            val fo = FileWriter(file)
//            fo.write(result)
//            fo.close()
//            println("Result also wrote into ${file.absolutePath}")
//        }
    }


    private fun parseJson(result: String,):String {
        val json = JSONObject(result)
        if (!json.has("access_token")) {
            // 返回没有access_token字段
            throw DemoException("access_token not obtained, $result")
        }
        if (!json.has("scope")) {
            // 返回没有scope字段
            throw DemoException("scopenot obtained, $result")
        }
        // scope = null, 忽略scope检查
        if (SCOPE != null && !json.getString("scope").contains(SCOPE)) {
            return ""
        }
        var token = json.getString("access_token")
        var expiresAt = System.currentTimeMillis() + json.getLong("expires_in") * 1000
        return token;
    }

    /**
     * 识别内容
     */
    fun goIndentifyContent(path:String,token: String,listener:AsrListener){
        //获取文件内容
        val content = getFileContent(path)
        if (content==null){
            listener.fail("读取文件失败")
            return
        }
        val speech = base64Encode(content)

        val params = JSONObject().apply {
            put("dev_pid", DEV_PID)
            // put("lm_id", LM_ID) // 测试自训练平台需要打开注释
            put("format", FORMAT)
            put("rate", RATE)
            put("token", token)
            put("cuid", CUID)
            put("channel", "1")
            put("len", content.size)
            put("speech", speech)
        }

        OkHttpUtils.getInstance().postJson(URL,params.toString(),emptyMap(),object :HttpCallback{
            override fun onSuccess(response: String) {
                var asrResult = DataUtils.jsonToObject(response, AsrResultEntity::class.java)
                var resultList = asrResult.result;
                if (resultList.size>0){
                    listener.success(resultList.get(0))
                }else{
                    listener.fail("识别失败"+asrResult.err_msg)
                }
            }

            override fun onFailure(errorMessage: String) {
                listener.fail("识别失败"+errorMessage)
            }
        })

//        println(params.toString())
//        val conn = URL(URL).openConnection() as HttpURLConnection
//        conn.connectTimeout = 5000
//        conn.requestMethod = "POST"
//        conn.setRequestProperty("Content-Type", "application/json; charset=utf-8")
//        conn.doOutput = true
//        conn.outputStream.write(params.toString().toByteArray())
//        conn.outputStream.close()
//        val result = ConnUtil.getResponseString(conn)
//
//        params.put("speech", "base64Encode(getFileContent(FILENAME))")
//        println("url is : $URL")
//        println("params is : ${params.toString()}")
//        Log.e("语音识别结果",result)
//        var asrResult = DataUtils.jsonToObject(result, AsrResultEntity::class.java)
//        var resultList = asrResult.result;
//        if (resultList.size>0){
//            listener.success(resultList.get(0))
//        }else{
//            listener.fail("识别失败"+asrResult.err_msg)
//        }
    }


//    @Throws(IOException::class, DemoException::class)
    fun run(path:String,listener:AsrListener) {


        val url = " http://aip.baidubce.com/oauth/2.0/token"
        var params = mapOf("grant_type" to "client_credentials", "client_id" to ConnUtil.urlEncode(APP_KEY),"client_secret" to ConnUtil.urlEncode(SECRET_KEY))
        OkHttpUtils.getInstance().get(url,params,object : HttpCallback {
            override fun onSuccess(response: String) {
                var token = parseJson(response);
                if (TextUtils.isEmpty(token)){
                    //失败
                    listener.fail("识别失败")
                }else{
                    //成功
                    goIndentifyContent(path,token,listener)
                }
            }

            override fun onFailure(errorMessage: String) {
                listener.fail("识别失败"+errorMessage)
            }
        })

//        thread {
//            val holder = TokenHolder(APP_KEY, SECRET_KEY, SCOPE)
//            holder.resfresh()
//            val token = holder.getToken()
//            if (METHOD_RAW) {
//                runRawPostMethod(token)
//            } else {
//                runJsonPostMethod(path,token,listener)
//            }
//        }


//        val holder = TokenHolder(APP_KEY, SECRET_KEY, SCOPE)
//        holder.resfresh()
//        val token = holder.getToken()
//        return if (METHOD_RAW) {
//            runRawPostMethod(token)
//        } else {
//            runJsonPostMethod(token)
//        }
    }

    @Throws(IOException::class, DemoException::class)
    private fun runRawPostMethod(token: String): String {
        var url2 = "$URL?cuid=${ConnUtil.urlEncode(CUID)}&dev_pid=$DEV_PID&token=$token"
        // 测试自训练平台需要打开以下信息
        // url2 = "$URL?cuid=${ConnUtil.urlEncode(CUID)}&dev_pid=$DEV_PID&lm_id=$LM_ID&token=$token"

        val contentTypeStr = "audio/$FORMAT; rate=$RATE"
        // println(url2)
        val content = getFileContent(FILENAME)
        val conn = URL(url2).openConnection() as HttpURLConnection
        conn.connectTimeout = 5000
        conn.setRequestProperty("Content-Type", contentTypeStr)
        conn.requestMethod = "POST"
        conn.doOutput = true
        conn.outputStream.write(content)
        conn.outputStream.close()
        println("url is $url2")
        println("header is Content-Type :$contentTypeStr")
        return ConnUtil.getResponseString(conn)
    }

    @Throws(DemoException::class, IOException::class)
    fun runJsonPostMethod(path:String,token: String,listener:AsrListener) {
        //获取文件内容
        val content = getFileContent(path)
        if (content==null){
            listener.fail("读取文件失败")
            return
        }
        val speech = base64Encode(content)

        val params = JSONObject().apply {
            put("dev_pid", DEV_PID)
            // put("lm_id", LM_ID) // 测试自训练平台需要打开注释
            put("format", FORMAT)
            put("rate", RATE)
            put("token", token)
            put("cuid", CUID)
            put("channel", "1")
            put("len", content.size)
            put("speech", speech)
        }

         println(params.toString())
        val conn = URL(URL).openConnection() as HttpURLConnection
        conn.connectTimeout = 5000
        conn.requestMethod = "POST"
        conn.setRequestProperty("Content-Type", "application/json; charset=utf-8")
        conn.doOutput = true
        conn.outputStream.write(params.toString().toByteArray())
        conn.outputStream.close()
        val result = ConnUtil.getResponseString(conn)

        params.put("speech", "base64Encode(getFileContent(FILENAME))")
        println("url is : $URL")
        println("params is : ${params.toString()}")
        Log.e("语音识别结果",result)
        var asrResult = DataUtils.jsonToObject(result, AsrResultEntity::class.java)
        var resultList = asrResult.result;
        if (resultList.size>0){
            listener.success(resultList.get(0))
        }else{
            listener.fail("识别失败"+asrResult.err_msg)
        }
//        {"corpus_no":"7569439111138732236","err_msg":"success.","err_no":0,"result":["给我拍张照。"],"sn":"450294714351762397380"}
//        return result
    }

    @Throws(DemoException::class, IOException::class)
    private fun getFileContent(filePath: String): ByteArray? {
//        val file = File(filename)

//        val file = File(FileUtil.getVoicePath(mContext))
        val file = File(filePath)

        if (!file.canRead()) {
            return null
        }

        FileInputStream(file).use { steam ->
            return ConnUtil.getInputStreamContent(steam)
        }
    }

    private fun base64Encode(content: ByteArray): String {
        /**
         * Base64.Encoder encoder = Base64.getEncoder(); // JDK 1.8  推荐方法
         * String str = encoder.encodeToString(content);
         */
        val chars = Base64Util.encode(content) // 1.7 及以下，不推荐，请自行跟换相关库
        return String(chars)
    }
}